package com.bascker.algorithm.practice.dp;

import com.bascker.algorithm.common.util.ValidUtils;

/**
 * 最小路径和：给定一个包含非负整数的 m x n 网格，请找出一条从左上角到右下角的路径，使得路径上的数字总和为最小。
 * Note: 每次只能向下或者向右移动一步。
 * <p>
 * in:                  out: 7
 * [
 * [1,3,1],
 * [1,5,1],
 * [4,2,1]
 * ]
 * <p>
 * 1->3->1->1->1 的总和最小
 *
 * @apiNote from leetcode T64
 */
public class MinPath {

    /**
     * 假定 dp(i, j) 表示从起点到 (i, j) 的最小路径和, 则 dp 方程如下所示:
     * dp(i, j) = min{dp(i - 1, j), dp(i, j - 1)} + grid[i][j]
     */
    public int minPath(final int[][] grid) {
        if (ValidUtils.isEmpty(grid)) {
            return 0;
        }

        int m = grid.length;
        int n = grid[0].length;

        int[][] dp = new int[m][n];
        dp[0][0] = grid[0][0];

        // 从上边界出发
        for (int i = 1; i < m; i++) {
            dp[i][0] = grid[i][0] + dp[i - 1][0];
        }

        // 从左边界出发
        for (int j = 1; j < n; j++) {
            dp[0][j] = grid[0][j] + dp[0][j - 1];
        }

        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }


        return dp[m - 1][n - 1];
    }

}
